/*
	* Entourage
	* Copyright 2011 INF532@Galatasaray University & Vincent Labatut
	*
	* This file is part of Entourage.
	*
	* Entourage is free software: you can redistribute it and/or modify
	* it under the terms of the GNU General Public License as published by
	* the Free Software Foundation, either version 3 of the License, or
	* (at your option) any later version.
	*
	* Entourage is distributed in the hope that it will be useful,
	* but WITHOUT ANY WARRANTY; without even the implied warranty of
	* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
	* GNU General Public License for more details.
	*
	* You should have received a copy of the GNU General Public License
	* along with Entourage. If not, see <http://www.gnu.org/licenses/>.
	*
	*/
package com.appspot.entourage.databasemanager;

import java.util.List;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.Query;

import com.appspot.entourage.common.*;
import com.appspot.entourage.explorer.Explorer;
//import com.appspot.entourage.*;

/**
 * This class allows to make interface, so to save, load and reload data 
 * about person and the links.
 * @author Yavuz BAYHANTOPCU <yavuz.bayhantopcu@gmail.com>
 * @version 1
 * @see PersonDB
 * @see LinkDB
 */

public class DataBaseManager {
	
	static EntityManagerFactory emf = Persistence.createEntityManagerFactory("transactions-optional");
	static EntityManager em = emf.createEntityManager();
	
		
	/**
	 * This method allows to insert a link between two person and define link weight.
	 * @param The source person and list to all of his linked person.
	 * @author Yavuz Bayhantopcu <yavuz.bayhantopcu@gmail.com>
	 * @see LinkDB
	 * @see PersonDB
	 */
	public static void insertLinks(Person source, List<Person> targets) {

		String sourceGuid=source.getGuid();
		
		EntityTransaction entr=em.getTransaction();
		Query q1 = em.createQuery("SELECT p FROM PersonDB p WHERE p.guid=:sourceGuid");
		q1.setParameter("sourceGuid", sourceGuid);

		PersonDB theSource = null;
		try
		{
			theSource=(PersonDB)q1.getSingleResult();
		}
		catch(Exception e)
		{}
		
		PersonDB theTarget = null;
		if (theSource==null)
			return;
		
		for(Person target: targets){
			
			String targetGuid=target.getGuid();
			Query q2=em.createQuery("SELECT p FROM PersonDB p WHERE p.guid=:targetGuid");
			q2.setParameter("targetGuid", targetGuid);
			try
			{
				theTarget=(PersonDB)q2.getSingleResult();
			}
			catch(Exception e)
			{}
			
			if (theTarget==null){
				String targetFullname=target.getFullName();
				String targetUrl=target.getUrl();
				PersonDB newPerson = new PersonDB(targetFullname, targetGuid, targetUrl);
				newPerson.setDistance(theSource.getDistance() + 1);
				entr.begin();
				em.persist(newPerson);
				entr.commit();
				
				theTarget=newPerson;
			}
			
			Query q3=em.createQuery("SELECT l FROM LinkDB l WHERE l.source=:theSource and l.target=:theTarget");
			q3.setParameter("theSource", theSource).setParameter("theTarget", theTarget);
			LinkDB theLink= null;
			try
			{
				theLink = (LinkDB)q3.getSingleResult();
			}
			catch(Exception e) {}
			
			if (theLink==null){
				LinkDB newLink = new LinkDB(theSource, theTarget, 1);
				
				entr.begin();
				em.persist(newLink);
				entr.commit();
			}
			else {
				int weight=theLink.getWeight();
				theLink.setWeight(weight++);
			}
		}
		entr.begin();
		theSource.setProcessed(true);
		entr.commit();
	}
	
	/**
	 * This method give the next person who will be the next Source person
	 * @return The next person to treat.
	 * @author Yavuz Bayhantopcu <yavuz.bayhantopcu@gmail.com>
	 * @see LinkDB
	 * @see PersonDB
	 */
	public static Person getNextPerson() {
		Query q4=em.createQuery("SELECT * FROM PersonDB WHERE processed=:false");
		q4.setParameter("false", "false");
		PersonDB theNext= null;
		try
		{
			theNext = (PersonDB)q4.getSingleResult();
		}catch(Exception e){}
		
		return new Person(theNext.getFullname(), theNext.getGuid(), theNext.getUrl()); //theNext;
	}
	
	
	/**
	 * This method define the maximum radius to the Target person
	 * @param The radius number.
	 * @author Yavuz Bayhantopcu <yavuz.bayhantopcu@gmail.com>
	 * @throws Exception 
	 * @see LinkDB
	 * @see PersonDB
	 */
	public static void init(int radius, Person initPerson) throws Exception {
		EntityTransaction entr=em.getTransaction();
		entr.begin();
		try{
			
			DatumDB ddb = new DatumDB();
			ddb.setTitle("Radius");
			ddb.setValue(radius);
			DatumDB ddb2 = new DatumDB();
			ddb2.setTitle("Status");
			ddb2.setValue(Explorer.NOT_STARTED);
			PersonDB pers = new PersonDB(initPerson.getFullName(), initPerson.getGuid(), initPerson.getUrl());
			pers.setProcessed(false);
			pers.setDistance(0);
			
			// Clears all records from the database
			Query q=em.createQuery("DELETE FROM DatumDB");
			q.executeUpdate();
			Query q2=em.createQuery("DELETE FROM LinkDB");
			q2.executeUpdate();	
			Query q3=em.createQuery("DELETE FROM PersonDB");
			q3.executeUpdate();		
			//////
			em.persist(ddb);
			em.persist(ddb2);
			em.persist(pers);
			entr.commit();
		}
		catch(Exception ex){
			entr.rollback();
			throw ex;
		}
	}	
	

	/**
	 * This method sets the status 
	 * @param status Status to set.
	 * @author Berk PELENK <bpelenk@beengames.com>
	 * @throws Exception 
	 * @see DatumDB
	 */
	public static void setStatus(int status) throws Exception {

		EntityTransaction entr=em.getTransaction();
		entr.begin();
		try{
			
			Query q=em.createQuery("SELECT l FROM DatumDB l WHERE l.Title=:status");
			q.setParameter("status", "Status");	
			List results = q.getResultList();
			
			DatumDB row;
			if(results.size() == 0)
			{
				row = new DatumDB();
				row.setTitle("Status");
			}
			else{
				row = (DatumDB)results.get(0);
				System.out.println("result found!");
				
			}
			
			row.setValue(status);
		}catch(Exception ex){
			entr.rollback();
			throw ex;
		}
			entr.commit();
	}

	/**
	 * This method returns the status
	 * @author Berk PELENK <bpelenk@beengames.com>
	 * @see DatumDB
	 */
	public static int getStatus() {

		EntityTransaction entr=em.getTransaction();
		entr.begin();
		Query q=em.createQuery("SELECT l FROM DatumDB l WHERE l.Title=:status");
		q.setParameter("status", "Status");	
		DatumDB row = null;
		try
		{
			row = (DatumDB)q.getSingleResult();
		}catch(Exception e){}
		
		if(row == null || row.getValue() == null)
		{
			return Explorer.NOT_STARTED;
		}
		
		return (Integer)row.getValue();
	}
	
	/**
	 * This method return a person that his fullname is sname
	 * @param the sname
	 * @author Zakaria BOUHAMIDI <zakariabouhamidi@hotmail.com>
	 * @see Cache
	 */
	public static Cache searchFullnameCache(String sname) {

		Query q=em.createQuery("SELECT c FROM Cache c WHERE c.fullname=:sname");
		q.setParameter("sname", sname);
		Cache theperson= null;
		try
		{
			theperson = (Cache)q.getSingleResult();
		}catch(Exception e){}
		
		return theperson;
	}
	
	/**
	 * This method return a person that his fullname is sname
	 * @param the sname
	 * @param the sguid
	 * @author Zakaria BOUHAMIDI <zakariabouhamidi@hotmail.com>
	 * @see Cache
	 */
	public static void insertNewPerson(String sfn , String sguid) {

		EntityTransaction entr=em.getTransaction();
		Cache newPerson = new Cache(sfn,sguid);
		entr.begin();
		em.persist(newPerson);
		entr.commit();
		//em.close();
	}
	
	public void getLogs(int results){
		
	}
	
	@SuppressWarnings("unchecked")
	public List<LinkDB> getRelations(String searchKey, int startIndex, int results){
		Query q;
		if(searchKey == null || searchKey == "")
		{
			q = em.createQuery("SELECT c FROM LinkDB c WHERE c.source=:theSource or c.target=:theTarget");
			q.setParameter("theSource", searchKey).setParameter("theTarget", searchKey);
		}
		else
			q = em.createQuery("SELECT c FROM LinkDB c");
		
		q.setFirstResult(startIndex);
		q.setMaxResults(results);
		return (List<LinkDB>) q.getResultList();
	}
	
	@SuppressWarnings("unchecked")
	public List<PersonDB> getPersons(){
		Query q=em.createQuery("SELECT c FROM PersonDB c");
		return (List<PersonDB>)q.getResultList();
	}
}


